home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / demos / audio / amesh / aifflib.c next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  21.2 KB  |  862 lines

  1. /*
  2.  * Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17.  
  18. /*
  19.  * aifflib --
  20.  *
  21.  *    A library for reading and writing AIFF files
  22.  *
  23.  *        Chris Schoeneman     - 1991
  24.  *        (borrowed heavily from playaiff and recordaiff)
  25.  */
  26.  
  27. #include <stdio.h>
  28. #include <string.h>
  29. #include <errno.h>
  30. #include <math.h>
  31. #include <audio.h>
  32. #include "aifflib.h"
  33.  
  34. /* AIFF file typedef's and defines */
  35. typedef struct
  36. {
  37.     long samprate;
  38.     long nchannels;
  39.     long sampwidth;
  40. } audio_params_t;
  41.  
  42. typedef struct
  43. {
  44.     char id[4];
  45.     long size;
  46. } chunk_header_t;
  47.  
  48. #define CHUNK_ID     4
  49. #define CHUNK_HEADER 8
  50.  
  51. typedef struct
  52. {
  53.     chunk_header_t header;
  54.     int file_position;  /* not in AIFF file */
  55.     char type[4]; /* should contain 'AIFF' for any audio IFF file */
  56. } form_chunk_t;
  57.  
  58. #define FORM_CHUNK      12  /* including the header */ 
  59. #define FORM_CHUNK_DATA 4   
  60.  
  61. #define COMM_CHUNK      26   /* including the header */
  62. #define COMM_CHUNK_DATA 18
  63.  
  64. typedef struct
  65. {
  66.     chunk_header_t header;
  67.     int file_position;            /* not in AIFF file */
  68.     short nchannels;
  69.     unsigned long nsampframes;
  70.     short sampwidth;
  71.     long samprate;              /* not in AIFF file */
  72. } comm_chunk_t;
  73.  
  74.  
  75. #define SSND_CHUNK      16   /* including the header */
  76. #define SSND_CHUNK_DATA 8
  77.  
  78. typedef struct
  79. {
  80.     chunk_header_t header;
  81.     unsigned long offset;
  82.     unsigned long blocksize;
  83.  
  84.     long file_position; /* not in AIFF file */
  85.     long sample_bytes; /* not in AIFF file */
  86. } ssnd_chunk_t;
  87. /* end of AIFF typedef's and defines */
  88.  
  89. #define    MAXFILES    20
  90.  
  91. enum { FORM = 0, COMM = 1, SSND = 2};
  92.  
  93. #define    DEFAULT_CHANNELS    2
  94. #define    DEFAULT_WIDTH        16
  95. #define    DEFAULT_RATE        48000
  96.  
  97. static int        busy[MAXFILES],
  98.             ssnd_remaining[MAXFILES],
  99.             files = -1;
  100. static long        writepos[MAXFILES][3];
  101. static FILE*        aifffd[MAXFILES];
  102. static audio_params_t    audioparams[MAXFILES];
  103.  
  104. int        AIFFerrno;
  105. static char    *AIFFerrstr[]={
  106.             "",
  107.             "too many open files",
  108.             "cannot open file",
  109.             "invalid file id",
  110.             "invalid data size",
  111.             "invalid header",
  112.             "not an AIFF file",
  113.             "no FORM header",
  114.             "invalid chunk",
  115.             "write failure",
  116.             "audio parameters are fixed",
  117.             "unsupported number of channels",
  118.             "unsupported sample width",
  119.             "unsupported sample rate"};
  120.  
  121. static int    widthtobytes(int width);
  122. static double    ConvertFromIeeeExtended(char*);
  123. static void    ConvertToIeeeExtended(double, char*);
  124.  
  125. /*************************************************************************
  126.  **    routines to read and write the AIFF format chunks        **
  127.  *************************************************************************/
  128. /* convert bytes in big endian order to a short */
  129. static short    align_short(char* buf)
  130. {
  131.   int i;
  132.   union { unsigned char b[sizeof(short)]; short s; } align_short;
  133.  
  134.   for (i = 0; i < sizeof(short); i++) align_short.b[i] = *buf++;
  135.   return align_short.s;
  136. }
  137.  
  138. /* convert bytes in big endian order to a long */
  139. static long    align_long(char* buf)
  140. {
  141.   int i;
  142.   union { unsigned char b[sizeof(long)]; long l; } align_long;
  143.  
  144.   for (i = 0; i < sizeof(long); i++) align_long.b[i] = *buf++;
  145.   return align_long.l;
  146. }
  147.  
  148. /* convert short to bytes in big endian order */
  149. static void    short_align(char* buf, short s)
  150. {
  151.   int i;
  152.   char *scan = (char*)&s;
  153.  
  154.   for (i = 0; i < sizeof(short); i++) *buf++ = *scan++;
  155. }
  156.  
  157. /* convert long to bytes in big endian order */
  158. static void     long_align(char* buf, long l)
  159. {
  160.   int i;
  161.   char *scan = (char*)&l;
  162.  
  163.   for (i = 0; i < sizeof(long); i++) *buf++ = *scan++;
  164. }
  165.  
  166. static int      skip_chunk(AIFFfile fd, chunk_header_t* chunk_header)
  167. {
  168.   fseek(aifffd[fd], chunk_header->size, SEEK_CUR);
  169. }
  170.  
  171. static int    read_chunk_header(AIFFfile fd, chunk_header_t *chunk_header)
  172. {
  173.   char buf[CHUNK_HEADER];
  174.   int i;
  175.  
  176.   if ((i = fread(buf, 1, CHUNK_HEADER, aifffd[fd])) != CHUNK_HEADER) return i;
  177.  
  178.   for (i=0; i<4; i++) chunk_header->id[i] = buf[i];
  179.   chunk_header->size = align_long(buf+4);
  180.  
  181.   return CHUNK_HEADER;
  182. }
  183.  
  184. static int    read_form_chunk(AIFFfile fd, chunk_header_t *chunk_header,
  185.             form_chunk_t *form_data)
  186. {
  187.   char buf[FORM_CHUNK_DATA];
  188.  
  189.   if (chunk_header->size < 0) {
  190.     AIFFerrno = AIFF_BADDATASIZE;
  191.     return -1;
  192.   }
  193.   else if (chunk_header->size == 0) {
  194.     AIFFerrno = AIFF_BADDATASIZE;
  195.     return -1;
  196.   }
  197.  
  198.   if (fread(buf, 1, FORM_CHUNK_DATA, aifffd[fd]) != FORM_CHUNK_DATA) {
  199.     AIFFerrno = AIFF_BADHEADER;
  200.     return -1;
  201.   }
  202.   if (strncmp(buf, "AIFF", 4)) {
  203.     AIFFerrno = AIFF_NOTAIFF;
  204.     return -1;
  205.   }
  206.   return 0;
  207. }
  208.  
  209. static int    read_comm_chunk(AIFFfile fd, chunk_header_t *chunk_header)
  210. {
  211.   int i;
  212.   char buf[COMM_CHUNK_DATA+1];
  213.   comm_chunk_t comm_data;
  214.  
  215.   if (fread(buf, 1, COMM_CHUNK_DATA, aifffd[fd]) != COMM_CHUNK_DATA) {
  216.     AIFFerrno = AIFF_BADCHUNK;
  217.     return -1;
  218.   }
  219.  
  220.   comm_data.nchannels = align_short(buf);
  221.   comm_data.nsampframes = align_long(buf+4);
  222.   comm_data.sampwidth = align_short(buf+6);
  223.  
  224.     /*
  225.      * the sample rate value from the common chunk is an 80-bit IEEE extended
  226.      * floating point number:
  227.      * [s bit] [15 exp bits (bias=16383)] [64 mant bits (leading 1 not hidden)]
  228.      *
  229.      * turns out we can just grab bytes 2 and 3 (if bytes numbered 0 ... 9)
  230.      * and cast them as an integer: the integer value equals the sample rate
  231.      */
  232.   comm_data.samprate = (long)ConvertFromIeeeExtended(buf+8);
  233.  
  234.   audioparams[fd].samprate = comm_data.samprate;
  235.   audioparams[fd].nchannels = comm_data.nchannels;
  236.   audioparams[fd].sampwidth = comm_data.sampwidth;
  237.  
  238.   if (widthtobytes(audioparams[fd].sampwidth) == -1) {
  239.     AIFFerrno = AIFF_BADWIDTH;
  240.     audioparams[fd].sampwidth = DEFAULT_WIDTH;
  241.     return -1;
  242.   }
  243.   return 0;
  244. }
  245.  
  246. /* AIFFread calls this if there is no more sound data in the current
  247.  * SSND chunk.  It searches for the next block and sets the
  248.  * ssnd_remaining entry to the length of the block */
  249. static void    read_ssnd_chunk(AIFFfile fd)
  250. {
  251.   char buf[SSND_CHUNK_DATA];
  252.   int i;
  253.   chunk_header_t chunk_header;
  254.  
  255.   /* if no sound left, search for next SSND block */
  256.   /* NOTE: all chunks have been read through and checked for 
  257.    * validity, so we assume read_chunk_header either returns
  258.    * zero for end of file or CHUNK_HEADER for a good block */ 
  259.   while (read_chunk_header(fd, &chunk_header) != 0) {
  260.     if (!strncmp(chunk_header.id, "SSND", 4)) {
  261.       fread(buf, 1, SSND_CHUNK_DATA, aifffd[fd]);
  262.       ssnd_remaining[fd] = chunk_header.size - 2*sizeof(long);
  263.       if (ssnd_remaining[fd] != 0) break;
  264.     }
  265.     else skip_chunk(fd, &chunk_header);
  266.   }
  267. }
  268.  
  269. static int      write_form_chunk(AIFFfile fd)
  270. {
  271.   char buf[FORM_CHUNK];
  272.   int i;
  273.  
  274.   strncpy(buf, "FORM", 4);        /* form header id */
  275.   for (i=0; i<sizeof(long); i++)  /* form header size  - do later */
  276.     buf[i+4] = 0x00;
  277.   strncpy(buf+4+sizeof(long), "AIFF", 4);
  278.  
  279.   writepos[fd][FORM] = ftell(aifffd[fd]);
  280.  
  281.   if (fwrite(buf, 1, FORM_CHUNK, aifffd[fd]) != FORM_CHUNK)
  282.     { AIFFerrno = AIFF_WRITEFAILURE; return -1; }
  283.  
  284.   return 0;
  285. }
  286.  
  287. static int    write_comm_chunk(AIFFfile fd)
  288. {
  289.   char buf[COMM_CHUNK];
  290.   int i;
  291.  
  292.   strncpy(buf, "COMM", 4);            /* chunk id */
  293.   long_align(buf+4,COMM_CHUNK_DATA);        /* chunk data size */
  294.   short_align(buf+4+sizeof(long),        /* number channels */
  295.     audioparams[fd].nchannels);
  296.   long_align(buf+4+sizeof(long)+sizeof(short),    /* nsample frames */
  297.     0L);
  298.   short_align(buf+4+2*sizeof(long)+sizeof(short), /* sample width */
  299.     audioparams[fd].sampwidth);
  300.   ConvertToIeeeExtended((double)audioparams[fd].samprate, /* sample rate */
  301.     buf + 4 + 2*sizeof(long) + 2*sizeof(short));
  302.  
  303.   writepos[fd][COMM] = ftell(aifffd[fd]);
  304.  
  305.   if (fwrite(buf, 1, COMM_CHUNK, aifffd[fd]) != COMM_CHUNK)
  306.     { AIFFerrno = AIFF_WRITEFAILURE; return -1; }
  307.  
  308.   ssnd_remaining[fd] = 0;
  309.  
  310.   return 0;
  311. }
  312.  
  313. static int    write_ssnd_chunk(AIFFfile fd)
  314. {
  315.   char buf[SSND_CHUNK];
  316.   int i;
  317.  
  318.   strncpy(buf, "SSND", 4);
  319.   for (i=0; i<3*sizeof(long); i++)  /* chunk data size */
  320.     buf[i+4] = 0x00;
  321.  
  322.   writepos[fd][SSND] = ftell(aifffd[fd]);
  323.  
  324.   if (fwrite(buf, 1, SSND_CHUNK, aifffd[fd]) != SSND_CHUNK)
  325.     { AIFFerrno = AIFF_WRITEFAILURE; return -1; }
  326.  
  327.   return 0;
  328. }
  329.  
  330. static int    update_form_chunk(AIFFfile fd, long total_bytes)
  331. {
  332.   fseek(aifffd[fd], writepos[fd][FORM]+4, SEEK_SET);
  333.   total_bytes -= CHUNK_HEADER;
  334.  
  335.   if (fwrite(&total_bytes, 1, sizeof(long), aifffd[fd]) != sizeof(long))
  336.     { AIFFerrno = AIFF_WRITEFAILURE; return -1; }
  337.  
  338.   return 0;
  339. }
  340.  
  341. static int    update_comm_chunk(AIFFfile fd, long sample_frames)
  342. {
  343.   fseek(aifffd[fd], writepos[fd][COMM]+CHUNK_HEADER+sizeof(short), SEEK_SET);
  344.  
  345.   if (fwrite(&sample_frames, 1, sizeof(long), aifffd[fd]) != sizeof(long))
  346.     { AIFFerrno = AIFF_WRITEFAILURE; return -1; }
  347.  
  348.   return 0;
  349. }
  350.  
  351. static int    update_ssnd_chunk(AIFFfile fd, long sample_bytes)
  352. {
  353.   fseek(aifffd[fd], writepos[fd][SSND] + CHUNK_ID, SEEK_SET);
  354.   sample_bytes += SSND_CHUNK_DATA;
  355.  
  356.   if (fwrite(&sample_bytes, 1, sizeof(long), aifffd[fd]) != sizeof(long))
  357.     { AIFFerrno = AIFF_WRITEFAILURE; return -1; }
  358.  
  359.   return 0;
  360. }
  361.  
  362. static AIFFfile    myopen(const char* filename, const char* dir)
  363. {
  364.   int i;
  365.   FILE* fd;
  366.  
  367.   /* find first available space in table */
  368.  
  369.   for (i = 0; i < MAXFILES; i++)
  370.     if (!busy[i]) break;
  371.   if (i == MAXFILES) {
  372.     AIFFerrno = AIFF_NOMEM;
  373.     return -1;
  374.   }
  375.  
  376.   /* open file */
  377.  
  378.   fd = fopen(filename, dir);
  379.   if (!fd) {
  380.     AIFFerrno = AIFF_OPENFAILURE;
  381.     return -1;
  382.   }
  383.  
  384.   /* fill table entries */
  385.  
  386.   aifffd[i] = fd;
  387.   busy[i] = *dir;
  388.   files++;
  389.  
  390.   return (AIFFfile)i;
  391. }
  392.  
  393. static int    myclose(AIFFfile fd)
  394. {
  395.   busy[fd] = 0;
  396.   files--;
  397.   return fclose(aifffd[fd]);
  398. }
  399.  
  400. AIFFfile    AIFFopen(const char* filename, const char* dir)
  401. {
  402.   AIFFfile fd;
  403.   int n;
  404.   chunk_header_t chunk_header;
  405.   form_chunk_t form_data;
  406.  
  407.   fd = myopen(filename, dir);
  408.   if (fd < 0) return fd;
  409.  
  410.   switch (dir[0]) {
  411.     case 'r': {
  412.       chunk_header_t chunk_header;
  413.       form_chunk_t form_data;
  414.       long past_header;
  415.  
  416.       if (read_chunk_header(fd, &chunk_header) != CHUNK_HEADER) {
  417.     myclose(fd);
  418.     AIFFerrno = AIFF_BADHEADER;
  419.     return -1;
  420.       }
  421.  
  422.       if (strncmp(chunk_header.id, "FORM", 4)) {    /* form container */
  423.     AIFFerrno = AIFF_NOFORMCHUNK;
  424.     myclose(fd);
  425.     return -1;
  426.       }
  427.  
  428.       if (read_form_chunk(fd, &chunk_header, &form_data) < 0) {
  429.     myclose(fd);
  430.     return -1;
  431.       }
  432.  
  433.       /* remember where interesting stuff starts */
  434.  
  435.       past_header = ftell(aifffd[fd]);
  436.  
  437.       /* search for last COMM chunk */
  438.  
  439.       while ((n = read_chunk_header(fd, &chunk_header)) != 0) {
  440.     if (n == CHUNK_HEADER) {
  441.       if (!strncmp(chunk_header.id, "COMM", 4))
  442.         read_comm_chunk(fd, &chunk_header);
  443.       else 
  444.         skip_chunk(fd, &chunk_header);
  445.     }
  446.     else {
  447.       myclose(fd);
  448.       AIFFerrno = AIFF_BADHEADER;
  449.       return -1;
  450.     }
  451.       }
  452.  
  453.       /* set file pointer to beginning of interesting stuff */
  454.  
  455.       fseek(aifffd[fd], past_header, SEEK_SET);
  456.       ssnd_remaining[fd] = 0;
  457.       break;
  458.     }
  459.     case 'w': {
  460.       /* write the form chunk */
  461.  
  462.       if (write_form_chunk(fd) < 0) {
  463.     myclose(fd);
  464.     return -1;
  465.       }
  466.  
  467.       /* set ssnd_remaining to a bogus value as a flag to write the COMM */
  468.  
  469.       ssnd_remaining[fd] = -1;
  470.  
  471.       /* set default values for audio parameters */
  472.       AIFFsetchannels(fd,0);
  473.       AIFFsetwidth(fd,0);
  474.       AIFFsetrate(fd,0);
  475.  
  476.       break;
  477.     }
  478.   }
  479.  
  480.   return fd;
  481. }
  482.  
  483. int    AIFFclose(AIFFfile fd)
  484. {
  485.   if (fd < 0 || fd >= MAXFILES || !busy[fd])
  486.     { AIFFerrno = AIFF_BADFD; return -1; }
  487.  
  488.   if (busy[fd] == 'w') {
  489.     long total = ftell(aifffd[fd]);
  490.  
  491.     if (update_form_chunk(fd, total) < 0)
  492.       goto badwrite;
  493.     total -= FORM_CHUNK + COMM_CHUNK + SSND_CHUNK;
  494.     if (update_comm_chunk(fd, total / AIFFgetchannels(fd) 
  495.         / widthtobytes(AIFFgetwidth(fd))) < 0)
  496.       goto badwrite;
  497.     if (update_ssnd_chunk(fd, total) < 0)
  498.       goto badwrite;
  499.   }
  500.  
  501.   return myclose(fd);
  502.  
  503. badwrite:
  504.   myclose(fd);
  505.   return -1;
  506. }
  507.  
  508. int    AIFFwrite(AIFFfile fd, const void* buf, unsigned nsamp)
  509. {
  510.   int bytes_written;
  511.   unsigned nbyte;
  512.  
  513.   if (fd < 0 || fd >= MAXFILES || !busy[fd])
  514.     { AIFFerrno = AIFF_BADFD; return -1; }
  515.  
  516.   /* write COMM and SSND block headers if necessary */
  517.  
  518.   if (ssnd_remaining[fd] == -1) {
  519.     if (write_comm_chunk(fd) < 0)
  520.       { AIFFerrno = AIFF_WRITEFAILURE; return -1; }
  521.     if (write_ssnd_chunk(fd) < 0)
  522.       { AIFFerrno = AIFF_WRITEFAILURE; return -1; }
  523.   }
  524.  
  525.   /* convert number of samples to number of bytes */
  526.   nbyte = nsamp * widthtobytes(audioparams[fd].sampwidth);
  527.  
  528.   bytes_written = fwrite(buf, 1, nbyte, aifffd[fd]);
  529.  
  530.   /* convert bytes to samples */
  531.   return bytes_written / widthtobytes(audioparams[fd].sampwidth);
  532. }
  533.  
  534. int    AIFFread(AIFFfile fd, void* buf, unsigned nsamp)
  535. {
  536.   int bytes_read, nbyte;
  537.  
  538.   if (fd < 0 || fd >= MAXFILES || !busy[fd])
  539.     { AIFFerrno = AIFF_BADFD; return -1; }
  540.  
  541.   /* skip to next SSND block if necessary */
  542.  
  543.   if (ssnd_remaining[fd] == 0) read_ssnd_chunk(fd);
  544.  
  545.   /* convert number samples to number bytes */
  546.   nbyte = nsamp * widthtobytes(audioparams[fd].sampwidth);
  547.  
  548.   /* get samples */
  549.   /* FIXME:  AIFFread should always attempt to fill the buffer
  550.    *        even if has to read the next SSND block to
  551.    *        do it (and the one after that, etc.) */
  552.  
  553.   if (ssnd_remaining[fd] < nbyte)
  554.     bytes_read = fread(buf, 1, ssnd_remaining[fd], aifffd[fd]);
  555.   else
  556.     bytes_read = fread(buf, 1, nbyte, aifffd[fd]);
  557.   ssnd_remaining[fd] -= bytes_read;
  558.  
  559.   /* convert bytes to samples */
  560.   return bytes_read / widthtobytes(audioparams[fd].sampwidth);
  561. }
  562.  
  563. int    AIFFgetlength(AIFFfile fd)
  564. {
  565.   if (fd < 0 || fd >= MAXFILES || !busy[fd])
  566.     { AIFFerrno = AIFF_BADFD; return -1; }
  567.  
  568.   /* skip to next SSND block if necessary */
  569.   if (ssnd_remaining[fd] == 0) read_ssnd_chunk(fd);
  570.  
  571.   return ssnd_remaining[fd] / widthtobytes(audioparams[fd].sampwidth);
  572. }
  573.  
  574. int    AIFFgetchannels(AIFFfile fd)
  575. {
  576.   if (fd < 0 || fd >= MAXFILES || !busy[fd])
  577.     { AIFFerrno = AIFF_BADFD; return -1; }
  578.  
  579.   return audioparams[fd].nchannels;
  580. }
  581.  
  582. int    AIFFgetwidth(AIFFfile fd)
  583. {
  584.   if (fd < 0 || fd >= MAXFILES || !busy[fd])
  585.     { AIFFerrno = AIFF_BADFD; return -1; }
  586.  
  587.   return audioparams[fd].sampwidth;
  588. }
  589.  
  590. int    AIFFgetrate(AIFFfile fd)
  591. {
  592.   if (fd < 0 || fd >= MAXFILES || !busy[fd])
  593.     { AIFFerrno = AIFF_BADFD; return -1; }
  594.  
  595.   return audioparams[fd].samprate;
  596. }
  597.  
  598. int    AIFFsetchannels(AIFFfile fd, int channels)
  599. {
  600.   if (fd < 0 || fd >= MAXFILES || !busy[fd])
  601.     { AIFFerrno = AIFF_BADFD; return -1; }
  602.  
  603.   /* make sure file is write and we haven't written any sound yet */
  604.  
  605.   if (ssnd_remaining[fd] != -1)
  606.     { AIFFerrno = AIFF_PARAMSFIXED; return -1; }
  607.  
  608.   if (channels == 0) channels = DEFAULT_CHANNELS;
  609.   audioparams[fd].nchannels = channels;
  610.  
  611.   return 0;
  612. }
  613.  
  614. int    AIFFsetwidth(AIFFfile fd, int width)
  615. {
  616.   if (fd < 0 || fd >= MAXFILES || !busy[fd])
  617.     { AIFFerrno = AIFF_BADFD; return -1; }
  618.  
  619.   /* make sure file is write and we haven't written any sound yet */
  620.  
  621.   if (ssnd_remaining[fd] != -1)
  622.     { AIFFerrno = AIFF_PARAMSFIXED; return -1; }
  623.  
  624.   if (width == 0) width = DEFAULT_WIDTH;
  625.   audioparams[fd].sampwidth = width;
  626.  
  627.   return 0;
  628. }
  629.  
  630. int    AIFFsetrate(AIFFfile fd, int rate)
  631. {
  632.   if (fd < 0 || fd >= MAXFILES || !busy[fd])
  633.     { AIFFerrno = AIFF_BADFD; return -1; }
  634.  
  635.   /* make sure file is write and we haven't written any sound yet */
  636.  
  637.   if (ssnd_remaining[fd] != -1)
  638.     { AIFFerrno = AIFF_PARAMSFIXED; return -1; }
  639.  
  640.   if (rate == 0) rate = DEFAULT_RATE;
  641.   audioparams[fd].samprate = rate;
  642.  
  643.   return 0;
  644. }
  645.  
  646. static int    widthtobytes(int width)
  647. {
  648.   switch (width) {
  649.     case 8: return 1;
  650.     case 16: return 2;
  651.     case 24: return 4;        /* FIXME: is this 3 or 4 */
  652.     default: return -1;
  653.   }
  654. }
  655.  
  656. int    CONVERTchannelstoAL(int channels)
  657. {
  658.   switch (channels) {
  659.     case 1: return AL_MONO;
  660.     case 2: return AL_STEREO;
  661.     default: AIFFerrno = AIFF_BADCHANNELS; return -1;
  662.   }
  663. }
  664.  
  665. int    CONVERTALtochannels(int ALchannels)
  666. {
  667.   switch (ALchannels) {
  668.     case AL_MONO: return 1;
  669.     case AL_STEREO: return 2;
  670.     default: AIFFerrno = AIFF_BADCHANNELS; return -1;
  671.   }
  672. }
  673.  
  674. int    CONVERTwidthtoAL(int width)
  675. {
  676.   switch (width) {
  677.     case 8: return AL_SAMPLE_8;
  678.     case 16: return AL_SAMPLE_16;
  679.     case 24: return AL_SAMPLE_24;
  680.     default: AIFFerrno = AIFF_BADWIDTH; return -1;
  681.   }
  682. }
  683.  
  684. int    CONVERTALtowidth(int ALwidth)
  685. {
  686.   switch (ALwidth) {
  687.     case AL_SAMPLE_8: return 8;
  688.     case AL_SAMPLE_16: return 16;
  689.     case AL_SAMPLE_24: return 24;
  690.     default: AIFFerrno = AIFF_BADWIDTH; return -1;
  691.   }
  692. }
  693.  
  694. int    CONVERTratetoAL(int rate)
  695. {
  696.   switch (rate) {
  697.     case 48000: return AL_RATE_48000;
  698.     case 44100: return AL_RATE_44100;
  699.     case 32000: return AL_RATE_32000;
  700.     case 22050: return AL_RATE_22050;
  701.     case 16000: return AL_RATE_16000;
  702.     case 11025: return AL_RATE_11025;
  703.     case 8000: return AL_RATE_8000;
  704.     default: AIFFerrno = AIFF_BADRATE; return -1;
  705.   }
  706. }
  707.  
  708. int    CONVERTALtorate(int ALrate)
  709. {
  710.   switch (ALrate) {
  711.     case AL_RATE_48000: return 48000;
  712.     case AL_RATE_44100: return 44100;
  713.     case AL_RATE_32000: return 32000;
  714.     case AL_RATE_16000: return 16000;
  715.     case AL_RATE_8000: return 8000;
  716.     default: AIFFerrno = AIFF_BADRATE; return -1;
  717.   }
  718. }
  719.  
  720. void    AIFFerror(const char* s)
  721. {
  722.   if (s && *s) fprintf(stderr,"%s: ",s);
  723.   fprintf(stderr,"%s\n",AIFFerrstr[-AIFFerrno]);
  724.   AIFFerrno = 0;
  725. }
  726.  
  727. char*    AIFFstrerror(int err)
  728. {
  729.   return AIFFerrstr[-err];
  730. }
  731.  
  732. /*
  733.  * Copyright (C) 1988-1991 Apple Computer, Inc.
  734.  * All rights reserved.
  735.  *
  736.  * Machine-independent I/O routines for IEEE floating-point numbers.
  737.  *
  738.  * NaN's and infinities are converted to HUGE_VAL or HUGE, which
  739.  * happens to be infinity on IEEE machines.  Unfortunately, it is
  740.  * impossible to preserve NaN's in a machine-independent way.
  741.  * Infinities are, however, preserved on IEEE machines.
  742.  *
  743.  * These routines have been tested on the following machines:
  744.  *    Apple Macintosh, MPW 3.1 C compiler
  745.  *    Apple Macintosh, THINK C compiler
  746.  *    Silicon Graphics IRIS, MIPS compiler
  747.  *    Cray X/MP and Y/MP
  748.  *    Digital Equipment VAX
  749.  *
  750.  *
  751.  * Implemented by Malcolm Slaney and Ken Turkowski.
  752.  *
  753.  * Malcolm Slaney contributions during 1988-1990 include big- and little-
  754.  * endian file I/O, conversion to and from Motorola's extended 80-bit
  755.  * floating-point format, and conversions to and from IEEE single-
  756.  * precision floating-point format.
  757.  *
  758.  * In 1991, Ken Turkowski implemented the conversions to and from
  759.  * IEEE double-precision format, added more precision to the extended
  760.  * conversions, and accommodated conversions involving +/- infinity,
  761.  * NaN's, and denormalized numbers.
  762.  */
  763. #ifndef HUGE_VAL
  764. # define HUGE_VAL HUGE
  765. #endif HUGE_VAL
  766.  
  767. # define UnsignedToFloat(u)    \
  768.      (((double)((long)(u - 2147483647L - 1))) + 2147483648.0)
  769. # define FloatToUnsigned(f)  \
  770.     ((unsigned long)(((long)(f - 2147483648.0)) + 2147483647L + 1))
  771.  
  772. /****************************************************************
  773.  * Extended precision IEEE floating-point conversion routines.
  774.  ****************************************************************/
  775.  
  776. static double    ConvertFromIeeeExtended(char *bytes)
  777. {
  778.     double    f;
  779.     long    expon;
  780.     unsigned long hiMant, loMant;
  781.  
  782.     expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF);
  783.     hiMant    =    ((unsigned long)(bytes[2] & 0xFF) << 24)
  784.             |    ((unsigned long)(bytes[3] & 0xFF) << 16)
  785.             |    ((unsigned long)(bytes[4] & 0xFF) << 8)
  786.             |    ((unsigned long)(bytes[5] & 0xFF));
  787.     loMant    =    ((unsigned long)(bytes[6] & 0xFF) << 24)
  788.             |    ((unsigned long)(bytes[7] & 0xFF) << 16)
  789.             |    ((unsigned long)(bytes[8] & 0xFF) << 8)
  790.             |    ((unsigned long)(bytes[9] & 0xFF));
  791.  
  792.     if (expon == 0 && hiMant == 0 && loMant == 0) {
  793.         f = 0;
  794.     }
  795.     else {
  796.         if (expon == 0x7FFF) {    /* Infinity or NaN */
  797.             f = HUGE_VAL;
  798.         }
  799.         else {
  800.             expon -= 16383;
  801.             f  = ldexp(UnsignedToFloat(hiMant), expon-=31);
  802.             f += ldexp(UnsignedToFloat(loMant), expon-=32);
  803.         }
  804.     }
  805.  
  806.     if (bytes[0] & 0x80)
  807.         return -f;
  808.     else
  809.         return f;
  810. }
  811.  
  812. static void    ConvertToIeeeExtended(double num, char *bytes)
  813. {
  814.     int    sign;
  815.     int expon;
  816.     double fMant, fsMant;
  817.     unsigned long hiMant, loMant;
  818.  
  819.     if (num < 0) {
  820.         sign = 0x8000;
  821.         num *= -1;
  822.     } else {
  823.         sign = 0;
  824.     }
  825.  
  826.     if (num == 0) {
  827.         expon = 0; hiMant = 0; loMant = 0;
  828.     }
  829.     else {
  830.         fMant = frexp(num, &expon);
  831.         if ((expon > 16384) || !(fMant < 1)) {    /* Infinity or NaN */
  832.             expon = sign|0x7FFF; hiMant = 0; loMant = 0; /* infinity */
  833.         }
  834.         else {    /* Finite */
  835.             expon += 16382;
  836.             if (expon < 0) {    /* denormalized */
  837.                 fMant = ldexp(fMant, expon);
  838.                 expon = 0;
  839.             }
  840.             expon |= sign;
  841.             fMant = ldexp(fMant, 32);
  842.             fsMant = floor(fMant);
  843.             hiMant = FloatToUnsigned(fsMant);
  844.             fMant = ldexp(fMant - fsMant, 32);
  845.             fsMant = floor(fMant);
  846.             loMant = FloatToUnsigned(fsMant);
  847.         }
  848.     }
  849.  
  850.     bytes[0] = expon >> 8;
  851.     bytes[1] = expon;
  852.     bytes[2] = hiMant >> 24;
  853.     bytes[3] = hiMant >> 16;
  854.     bytes[4] = hiMant >> 8;
  855.     bytes[5] = hiMant;
  856.     bytes[6] = loMant >> 24;
  857.     bytes[7] = loMant >> 16;
  858.     bytes[8] = loMant >> 8;
  859.     bytes[9] = loMant;
  860. }
  861.  
  862.